<script type="text/javascript" src="list_js/d3.js"></script>
<script type="text/javascript" src="list_js/d3.layout.js"></script>

<!-- uncomment for open list.html slone -->
<!-- script type="text/javascript" src="/jquery-1.11.1.min.js"></script -->

<!-------------------------------
    Site Layout
--------------------------------->
<script src="/sitelayout-shan.js" ></script>
<!-- script src="/sitelayout-GR.js" ></script -->

<!-------------------------------
    SCU control scripts start 
--------------------------------->
<script src="/socket.io/socket.io.js"></script>
<script src="/scucontrol/scuc_main.js" ></script>
<script src="/scucontrol/scuc_packet.js" ></script>
<script src="/scucontrol/scuc_util.js" ></script>
<script>
//var SCUC_gLayout=null ;
var list_soket_io=null ;

function SCUControl_init()
{
    local_log('SCUControl_init');
    list_soket_io = ScuControl_Init(onLayout,onUpdate) ;
}

/* Notification of Receive layout */
var onLayoutArrival=false ;
setTimeout(function () {checkReceiveLayout()},3000);
function checkReceiveLayout() {
    if( !onLayoutArrival )
        alert("정보 수신 실패. 다시 읽어주세요. (Windows F5)") ;
}

function onLayout(layout)
{
    onLayoutArrival = true ;
    
    local_log('onRecvLayout '+JSON.stringify(layout));
    //SCUC_gLayout = layout ;
    
    // update status
	var relays = vis.selectAll("[name^=relay_]").each(function(d) {
	    UpdateRelayItemState(d) ;
	    });
}

/* Notification of Receive update */
function onUpdate(update)
{
    //local_log('onUpdate '+JSON.stringify(update));

    // find item
    var lid = SCUC_get_lid_from_ids(update.bid,update.rid) ;
	var relays = vis.selectAll("[name="+lid+"]").each(function(d) {
	    UpdateRelayItemState(d) ;
	    });
	//$(layout)
}

// update relay state
function UpdateRelayItemState(d) {
    if( !d ) {
        local_log('UpdateRelayItemState null') ;
        return ;
    }
    
    // get relay id
    var ids = SCUC_get_ids_from_lid(d.lid) ;
    // get relay info
    var info = ScuControl_GetRelayInfo(0,ids[0],ids[1]) ;
    // set relay state
    d.state = info.status ;
    // set relay description
    if( 1==d.state ) {
        d.desc = GetTimeString(info.stime,info.etime) ;
    }
    else
        d.desc = '' ;

    local_log('UpdateRelayItemState '+ids[0]+'/'+ids[1]+', '+JSON.stringify(info));
}

/* get web state from relay status
    relay status
#define RELAY_STATUS_OFF        0x00
#define RELAY_STATUS_ON         0x01
#define RELAY_STATUS_AIR        0x02
#define RELAY_STATUS_COOLING    0x03
#define RELAY_STATUS_HEATING    0x04

#define RELAY_STATUS_PENDING    0x20    // pending or shutdown
#define RELAY_STATUS_UNKNOWN    0x40
#define RELAY_STATUS_NOTUSED    0x80
    
    web state 
        0 : off 
        1 : on 
        2 : mixed
        3 : unknown
*/
function GetItemWebStateFromRelayState(status) {
    var state = 3 ; // unknown
    if( 0==status      // off
        || 1==status   // on
        )
        state = status ;
    //else if( 64==status )
    //    state = 3 ; // unknown
    return state ;
}

function IsRelayWorking(status) {
    var bWork = false ;
    if( 0==status      // off
        || 1==status   // on
        )
        bWork = true ;
    return bWork ;
}

/* send set item (site/subset/relay) state command
    only support state 0 : off and 1 : on 
*/
function SetItemState(lid, state) {
    if( 0!=state && 1!=state ) {
    	local_log('SetItemState illegal state '+state) ;
    	return ;
    }

	dual_log('SetItemState(' + lid + ', ' + state + ')',list_soket_io);

	var relay_lids = new Array() ;

	/* make relay id array from lid "relay" */
	if( lid.substring(0,6)=="relay_" ) {
	    relay_lids.push(lid) ;
	}
	/* make relay id array from lid "subset" */
	else if( lid.substring(0,7)=="subset_" ) {
    	var subsets = vis.selectAll("[name="+lid+"]").each(function(d) {
    	    var relays = d.children ;
            for( i=0 ; i<relays.length ; i++ ) {
                //local_log('['+i+'] '+shallowStringify(relays[i]));
        	    relay_lids.push(relays[i].lid) ;
        	}
    	    });
	}
	/* make relay id array from lid "site" */
	else if( lid.substring(0,5)=="site_" ) {
    	var subsets = vis.selectAll("[name^=relay_]").each(function(d) {
    	    relay_lids.push(d.lid) ;
    	    });
	}
	else {
    	local_log('SetItemState unknown lid '+lid) ;
	}
	
	/* remove duplicated lid */
	var relay_lids_unique = new Array() ;
	$.each(relay_lids, function(i, el){
        if($.inArray(el, relay_lids_unique) === -1) relay_lids_unique.push(el);});

	local_log('SetItemState '+lid+' '+relay_lids_unique) ;
	
	/* set the relay */
	var a_relay_control = {} ;
	a_relay_control.list = new Array() ;
	for( i=0 ; i<relay_lids_unique.length ; i++ ) {
        var ids = SCUC_get_ids_from_lid(relay_lids_unique[i]) ;
	    var relay_control = {};
        relay_control.cid = 0 ;
        relay_control.bid = ids[0] ;
        relay_control.rid = ids[1] ;
        relay_control.state = state ;
        a_relay_control.list.push(relay_control) ;
	}
	a_relay_control.count = a_relay_control.list.length ;
    	
	ScuControl_SetRelayList(a_relay_control,list_soket_io) ;
}

function GetTimeString(stime,etime) 
{
    var str = ' ('+ScuControl_GetStimeString(stime,etime)+' ~ '+ScuControl_GetEtimeString(stime,etime)+')' ;
    return str ;
}

// get bid, rid from "Relay_<bid>_<rid>" string
function SCUC_get_ids_from_lid(lid) {
    var fields = lid.split('_') ;
    
    var ids = new Array();
    ids[0] = parseInt(fields[1]) ;
    ids[1] = parseInt(fields[2]) ;
	return ids ;
}

// get "Relay_<bid>_<rid>" string from bid, rid
function SCUC_get_lid_from_ids(bid,rid) {
	return 'relay_'+bid+'_'+rid ;
}
</script>
<!-------------------------------
    SCU control scripts end 
--------------------------------->

<style type="text/css">
#body {
  background: url(list_img/texture-noise.png);
  margin: 0;
  font-size: 22px;
  font-family: "Helvetica Neue", Helvetica;
}

.node circle {
  cursor: pointer;
  fill: #fff;
  stroke: steelblue;
  stroke-width: 2px;
}

.node text .description {
  font-size: 14px;
}

path.link {
  fill: none;
  stroke: #ccc;
  stroke-width: 1.5px;
}
</style>

<script type="text/javascript">
var pollingTimeout = 1000;
var circleRadio = 10;
var textMarginX = 16;

var isMobile = { 
Android: function() { return navigator.userAgent.match(/Android/i); }, 
BlackBerry: function() { return navigator.userAgent.match(/BlackBerry/i); }, 
iOS: function() { return navigator.userAgent.match(/iPhone|iPad|iPod/i); }, 
Opera: function() { return navigator.userAgent.match(/Opera Mini/i); }, 
Windows: function() { return navigator.userAgent.match(/IEMobile/i); }, 
any: function() { return (isMobile.Android() || isMobile.BlackBerry() || isMobile.iOS() || isMobile.Opera() || isMobile.Windows()); } };

var getLayout = function() {
	return layout;
};

var vis ;
$(function() {
	var m = [20, 120, 20, 120],
    w = 1280 - m[1] - m[3],
    h = 800 - m[0] - m[2],
    i = 0,
    root;
    
    if (isMobile.any()) {
    	circleRadio = 20;
    	textMarginX = 28;
    	
    	h = 1200 - m[0] - m[2],
    	$('body').css('font-size', '30px');
    	$('tspan.description').css('font-size', '20px');
    }
    
    var stateColors = [
        '#000',         // 0 off, black    
        'OrangeRed',    // 1 on, red
        '#fff',         // 2 mixed, white
        'grey'          // 3 unknown (not-connected), grey
        ];

	var tree = d3.layout.tree()
	    .size([h, w]);
	
	var diagonal = d3.svg.diagonal()
	    .projection(function(d) { return [d.y, d.x]; });
	
	vis = d3.select("#body").append("svg:svg")
	    .attr("width", w + m[1] + m[3])
	    .attr("height", h + m[0] + m[2])
		.append("svg:g")
	    .attr("transform", "translate(" + m[3] + "," + m[0] + ")");
	
	root = getLayout();
	root.x0 = h / 2;
	root.y0 = 0;

	// Initialize the display to show a few nodes.
	root.children.forEach(function() {
		toggleAll(this);
	});
	update(root);
	
	/* SCU control Init */
	SCUControl_init() ;
	
	//polling
	window._interval = setInterval(function() {
		updateState();
	}, pollingTimeout);
	
	function update(source) {
	  var duration = d3.event && d3.event.altKey ? 5000 : 500;
	
	  // Compute the new tree layout.
	  var nodes = tree.nodes(root).reverse();
	
	  // Normalize for fixed-depth.
	  nodes.forEach(function(d) { d.y = d.depth * 180; });
	  
	  //console.log('updating ' + source);
	
	  // Update the nodes??
	  var node = vis.selectAll("g.node")
	      .data(nodes, function(d) { return d.id || (d.id = ++i); });
	
	  // Enter any new nodes at the parent's previous position.
	  var nodeEnter = node.enter().append("svg:g")
	      //.attr("class", "node")
	      .attr("class", function(d) {
	      	var children = d.children || d._children;
	      	if (children && d.lid.lastIndexOf("subset_", 0) === 0) {
	      		var klass = "node";
	      		children.forEach(function(n, i){
	      			klass += " " + children[i].lid;
	      		});
	      		return klass;
	      	}
	      	return "node";
	      })
	      .attr("name", function(d) { return d.lid; }) // ? "node " + d.lid : "node"; })
	      .attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
	      .on("dblclick", function(d) { if (!d.parent) return; toggle(d); update(d); });
	
	  nodeEnter.append("svg:circle")
	      .attr("r", 1e-6)
	      .style("fill", function(d) { return getStateColor(d); })
	      .on("click", function(d) { show(d); onOff(d); });
	
	  var textNode = nodeEnter.append("svg:text")
	      .attr("x", function(d) { return d.children || d._children ? -1*textMarginX : textMarginX; })
	      .attr("dy", ".35em")
	      .attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; })
	      // .text(function(d) { 
	      	// if (d.desc) return "<tspan>" + d.name + '</tspan><tspan class="description">' + d.desc + "<tspan>";
	      	// return d.name;
	      	// })
	      .on("click", function(d) {if (!d.parent) return; toggle(d); update(d); })
	      .style("fill-opacity", 1e-6);
	      
	  textNode.append("svg:tspan")
			.text(function(d) {return d.name;})
			.attr("class", "name");
			
	  textNode.append("svg:tspan")
	      	.text("")
	      	.attr("dy", "-.2em")
		    .attr("class", "description");
	
	  // Transition nodes to their new position.
	  var nodeUpdate = node.transition()
	      .duration(duration)
	      .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; });
	
	  nodeUpdate.select("circle")
	      .attr("r", circleRadio)
	      .style("fill", function(d){ return getStateColor(d); });
	
	  nodeUpdate.select("text")
	      .style("fill-opacity", 1);
	
	  // Transition exiting nodes to the parent's new position.
	  var nodeExit = node.exit().transition()
	      .duration(duration)
	      .attr("transform", function(d) { return "translate(" + source.y + "," + source.x + ")"; })
	      .remove();
	
	  nodeExit.select("circle")
	      .attr("r", 1e-6);
	
	  nodeExit.select("text")
	      .style("fill-opacity", 1e-6);
	
	  // Update the links??
	  var link = vis.selectAll("path.link")
	      .data(tree.links(nodes), function(d) { return d.target.id; });
	
	  // Enter any new links at the parent's previous position.
	  link.enter().insert("svg:path", "g")
	      .attr("class", "link")
	      .attr("d", function(d) {
	        var o = {x: source.x0, y: source.y0};
	        return diagonal({source: o, target: o});
	      })
	    .transition()
	      .duration(duration)
	      .attr("d", diagonal);
	
	  // Transition links to their new position.
	  link.transition()
	      .duration(duration)
	      .attr("d", diagonal);
	
	  // Transition exiting nodes to the parent's new position.
	  link.exit().transition()
	      .duration(duration)
	      .attr("d", function(d) {
	        var o = {x: source.x, y: source.y};
	        return diagonal({source: o, target: o});
	      })
	      .remove();
	
	  // Stash the old positions for transition.
	  nodes.forEach(function(d) {
	    d.x0 = d.x;
	    d.y0 = d.y;
	  });
	}
	
	function toggleAll(d) {
    	if (d.children) {
	      	d.children.forEach(toggleAll);
	      	toggle(d);
    	}
	}
	
	// Toggle children.
	function toggle(d) {
	  if (d.children) {
	    d._children = d.children;
	    d.children = null;
	  } else {
	    d.children = d._children;
	    d._children = null;
	  }
	}
	
	// Show children.
	function showChildren(d) {
	  if (d.children) {
	    return;
	  } else {
	    d.children = d._children;
	    d._children = null;
	    update(d);
	  }
	}
	
	function show(d) {
	  if (d.children) {
	      d.children.forEach(show);
	      showChildren(d);
	  }
	  if (d._children) {
	      d._children.forEach(show);
	      showChildren(d);
	  }
	}

	//Toggle on-off
	function onOff(d) {
		if (d.children || d._children) {
			showChildren(d);
		}
		
		var onOff = d.state == 1 ? 0 : 1;

		// local_log('onOff ' + d.lid + ', ' + d.state + ')');
		SetItemState(d.lid, onOff);
	}
	
	function arraysEqual(a1, a2) {
    	return JSON.stringify(a1) == JSON.stringify(a2);
	}
	var lastOutput;

	function updateState() {
		vis.selectAll("[name^=relay_]").each(function(d) {
			var target = $('g[name=' + d.lid + ']');
			//console.log(target.find('tspan.description'), d.desc);
			target.find('circle').css("fill", function() { return getStateColor(d); });
		    //target.find('tspan.name').text(function(d) {return d.name;});
		    target.find('tspan.description').text(function() {if (d.desc) return d.desc; return ""});
		      
			if (d.parent) checkState(d.parent);
		});
		
		//update(root);
		// var onIds = getState();
		// if (arraysEqual(onIds, lastOutput)) {
			// //console.log('returning');
			// return;
		// }
// 		
		// console.log(onIds);
		// lastOutput = onIds;
		/* set off all relay and subset */
		// var subsets = vis.selectAll("[name^=relay_]").each(function(d) {setOff(d);});
		// vis.selectAll("[name^=subset_]").each(function(d) {
			// if (!d.children && d._children) {
				// d._children.forEach(function(n, i) {d._children[i].state = 0;});
				// setOff(d);
			// }
		// });
		
		// /* set on relay */
		// onIds.forEach(function(d, i) {
			// vis.selectAll("[name=" + onIds[i] + "]").each(function(n, k) {
				// setOn(n, k);
			// });
// 			
			// vis.selectAll("." + onIds[i]).each(function(d) {
				// if (!d.children && d._children) {
					// d._children.forEach(function(n, k) {if (d._children[k].lid == onIds[i]) d._children[k].state = 1;});
					// checkState(d);
				// }
			// });
		// });
		
	}
	
	function setOn(d, i) {
		d.state = 1;
		
		//console.log(d);
		if (d.parent) checkState(d.parent);
		update(d);
	}
	
	function setOff(d, i) {
		d.state = 0;
		if (d.parent) checkState(d.parent);
	}

	function getStateColor(d) {
	    // GetItemWebStateFromRelayState
        var circle_state ;
        if( 0==d.state      // off
            || 1==d.state   // on
            || 2==d.state   // mixed
            )
            circle_state = d.state ;
        else
            circle_state = 3 ; // unknown

		return stateColors[circle_state];
	}
	
	function checkState(d) {
        //if( d.lid.substring(0,5)=="site_" )
        //    local_log('checkState '+d.lid+' '+d.state) ;
	    
		var state = -1;
		var children = d.children || d._children;
		children.forEach(function(n){
            //if( d.lid.substring(0,5)=="site_" )
            //    local_log('  '+n.lid+' '+n.state) ;
			if (state < 0) {
				state = n.state;
			} 
			else if (state != n.state) 
			{
			    // set mixed state
			    var bMixed = true ;
    			// skip unknown to support off on subset
                if( d.lid.substring(0,7)=="subset_" && !IsRelayWorking(n.state) )
			        bMixed = false ;
			    
			    if( bMixed ) {
    				state = 2;
    				return;
    			}
			}
		});
		d.state = state;
		update(d);
		
		if (d.parent) {
			checkState(d.parent);
		}
	}
});
</script>
<div id="body">
</div>	